package com.rt.tmpt.security;

import com.rt.tmpt.dto.A2UserDto;
import com.rt.tmpt.dto.ConstantDto;
import com.rt.tmpt.dto.Result;
import com.rt.tmpt.service.ILoginFailureService;
import com.rt.tmpt.service.ISecurityV2Service;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/*
 *
 * UsernamePasswordAuthenticationFilter源码
    attemptAuthentication
        this.getAuthenticationManager()
            ProviderManager.java
                authenticate(UsernamePasswordAuthenticationToken authRequest)
                    AbstractUserDetailsAuthenticationProvider.java
                        authenticate(Authentication authentication)
                            P155 user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
                                DaoAuthenticationProvider.java
                                    P86 loadUserByUsername
 */
//@Component
@Slf4j
public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter{
    public static final String VALIDATE_CODE = "validateCode";
    public static final String USERNAME = "username";
    public static final String PASSWORD = "password";

    @Resource private ISecurityV2Service securityV2Service;
    @Resource private ILoginFailureService loginFailureService;
    //@Resource
    //private SessionRegistry sessionRegistry;


    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        //6次登录密码错误，锁定1小时
        int hourInt =1;
        int limitFailureTimes=6;

        if (!request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        //检测验证码
        HttpSession session = request.getSession();
        //System.out.println("v:"+session.getId());
        Object isLoginSuccessBack = session.getAttribute("isLoginSuccessBack");
        if(isLoginSuccessBack!=null){
            checkValidateCode(request);
        }

        String username = obtainUsername(request);
        String password = obtainPassword(request);
        String psdMd5 = password;
        /*String psdMd5 = "";
        try {
            //解密
            String keyPairLocation = Config.keyPairLocation;
            keyPairLocation = null;
            DecodeAction decodeAction = new DecodeAction(keyPairLocation);
            password = decodeAction.execute(password);
            //log.debug("password:"+password);
            //password by md5 for store
            psdMd5 = password+username;
            //log.debug("psdMd5:"+psdMd5);
            psdMd5 = MD5Util.toMD5ForApp(psdMd5);
            //log.debug("psdMd5:"+psdMd5);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AuthenticationServiceException("密码加解密出错！");
        }*/

        //验证用户账号与密码是否对应
        username = username.trim();

        A2UserDto userDto = securityV2Service.getUserByLoginname(username);
        if(userDto == null){
            throw new AuthenticationServiceException("用户名不存在！");
        }

        //登录次数限制-开始
        Result resultLoginLimit = loginFailureService.loginBefore(0, userDto.getId(),0, hourInt, limitFailureTimes);
        if(!resultLoginLimit.isSuccess()){
            throw new  AuthenticationServiceException(resultLoginLimit.getContentOnly());
        }

        if(!userDto.getPassword().toLowerCase().equals(psdMd5.toLowerCase())) {
            session.setAttribute("isLoginSuccessBack", -1);

            //登录次数限制-密码错误
            resultLoginLimit = loginFailureService.loginFailure(0, userDto.getId(),0, hourInt, limitFailureTimes);
            if(!resultLoginLimit.isSuccess()){
                throw new  AuthenticationServiceException("密码不正确");
            }

            throw new AuthenticationServiceException("密码不正确；"+resultLoginLimit.getContentOnly());
        }

        //login success , release data about the customer
        loginFailureService.loginRelease(0, userDto.getId(),0);

        //UsernamePasswordAuthenticationToken实现 Authentication
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, psdMd5.toLowerCase());
        // Place the last username attempted into HttpSession for views

        //用户名密码验证通过后,注册session
        //sessionRegistry.registerNewSession(request.getSession().getId(),authRequest.getPrincipal());

        // 允许子类设置详细属性
        setDetails(request, authRequest);

        // 运行UserDetailsService的loadUserByUsername 再次封装Authentication
        Authentication auth = this.getAuthenticationManager().authenticate(authRequest);
        session.removeAttribute("isLoginSuccessBack");
        session.setAttribute(ConstantDto.MagSystemDtoSession, userDto);

        securityV2Service.recordLastLoginInfo(userDto);


        //将认证信息放入 Session 中
        SecurityContextHolder.getContext().setAuthentication(auth);
        UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication() .getPrincipal();
        //System.out.println("=============:"+userDetails.getUsername());


        return auth;
    }


    protected void checkValidateCode(HttpServletRequest request) {
        HttpSession session = request.getSession();

        String sessionValidateCode = obtainSessionValidateCode(session);
        //让上一次的验证码失效
        session.setAttribute(VALIDATE_CODE, null);
        String validateCodeParameter = obtainValidateCodeParameter(request);
        if (StringUtils.isEmpty(validateCodeParameter) || !sessionValidateCode.equalsIgnoreCase(validateCodeParameter)) {
            throw new AuthenticationServiceException("验证码错误！");
        }
    }

    private String obtainValidateCodeParameter(HttpServletRequest request) {
        Object obj = request.getParameter(VALIDATE_CODE);
        return null == obj ? "" : obj.toString();
    }

    protected String obtainSessionValidateCode(HttpSession session) {
        Object obj = session.getAttribute(VALIDATE_CODE);
        return null == obj ? "" : obj.toString();
    }

    @Override
    protected String obtainUsername(HttpServletRequest request) {
        Object obj = request.getParameter(USERNAME);
        return null == obj ? "" : obj.toString();
    }

    @Override
    protected String obtainPassword(HttpServletRequest request) {
        Object obj = request.getParameter(PASSWORD);
        return null == obj ? "" : obj.toString();
    }


}
